package com.ruoyi.base.utils.date;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 时间工具类
 *
 * @author ruoyi
 */
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static String YYYY = "yyyy";

    public static String MM = "MM";

    public static String YYYYMMDD = "yyyyMMdd";

    public static String YYYYMM = "yyyyMM";

    public static String MMDD = "MMdd";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    public static String MM_DD_HH_MM = "MM-dd HH:mm";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前String型日期
     */
    public static String formatNow(String format) {
        return formatDate(format, new Date());
    }

    /**
     * 日期转字符串
     */
    public static String formatDate(String format, Date date) {
        return new SimpleDateFormat(format).format(date);
    }

    /**
     * 获取当前Date型日期
     */
    public static Date parseNow(String format) {
        return parseDate(format, new Date());
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object date) {
        if (date == null) {
            return null;
        }
        try {
            return parseDate(date.toString(), parsePatterns);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 日期型字符串转化为日期 格式
     *
     * @param format 格式
     * @param date   日期字符串
     */
    public static Date parseDate(String format, String date) {
        if (StringUtils.isBlank(date)) {
            return null;
        }

        try {
            return new SimpleDateFormat(format).parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期转化为日期 格式
     *
     * @param format 格式
     * @param date   日期
     */
    public static Date parseDate(String format, Date date) {
        if (date == null) {
            return null;
        }
        SimpleDateFormat sim = new SimpleDateFormat(format);
        try {
            return sim.parse(sim.format(date));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 年加法
     */
    public static Date addYear(Date date, int num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.YEAR, num);
        return calendar.getTime();
    }

    /**
     * 月加法
     */
    public static Date addMonth(Date date, int num) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, num);
        return calendar.getTime();
    }

    /**
     * 获取日期年
     */
    public static String getYear(Date date) {
        return String.valueOf(getIntYear(date));
    }

    /**
     * 获取年数字
     */
    public static int getIntYear(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.YEAR);
    }

    /**
     * 获取字符串形式年数字
     */
    public static String getStrYear(Date date) {
        return String.valueOf(getIntYear(date));
    }

    /**
     * 获取月数字
     */
    public static int getIntMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.MONTH) + 1;
    }

    /**
     * 获取日数字
     */
    public static int getIntDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.DATE);
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     */
    public static String getDateBetween(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 获取间隔天数
     */
    public static long getDaysBetween(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        return diff / nd;
    }

    /**
     * 计算两个时间相差毫秒数
     */
    public static long getmilliSeconds(Date endDate, Date nowDate) {
        // 获得两个时间的毫秒时间差异
        return endDate.getTime() - nowDate.getTime();
    }

    /**
     * 获取周开始日期
     */
    public static Date getWeekStartDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek == 0) {
            cal.add(Calendar.DATE, -7);
        }
        cal.add(Calendar.DATE, -dayOfWeek + 1);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取周结束日期
     */
    public static Date getWeekEndDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getWeekStartDate(date));
        cal.add(Calendar.DAY_OF_WEEK, 6);
        Date weekEndSta = cal.getTime();
        return getDayEndTime(weekEndSta);
    }

    /**
     * 获取月初日期
     */
    public static Date getMonthStartDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, 1);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取月末日期
     */
    public static Date getMonthEndDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return getDayEndTime(cal.getTime());
    }

    /**
     * 获取季度初日期
     */
    public static Date getSeasonStartDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        int month = cal.get(Calendar.MONTH) + 1;
        if (month <= 3) {
            month = 0;
            cal.set(Calendar.MONTH, month);
            cal.set(Calendar.DATE, 1);
            return getDayStartTime(cal.getTime());
        }
        if (month <= 6) {
            month = 3;
            cal.set(Calendar.MONTH, month);
            cal.set(Calendar.DATE, 1);
            return getDayStartTime(cal.getTime());
        }
        if (month <= 9) {
            month = 6;
            cal.set(Calendar.MONTH, month);
            cal.set(Calendar.DATE, 1);
            return getDayStartTime(cal.getTime());
        }
        if (month <= 12) {
            month = 9;
            cal.set(Calendar.MONTH, month);
            cal.set(Calendar.DATE, 1);
            return getDayStartTime(cal.getTime());
        }

        cal.set(Calendar.MONTH, month);
        cal.set(Calendar.DATE, 1);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取季度末日期
     */
    public static Date getSeasonEndDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(getSeasonStartDate(date));
        cal.add(Calendar.MONTH, 2);
        return getMonthEndDate(cal.getTime());
    }

    /**
     * 获取季度初日期
     */
    public static Date getSeasonStartDate(int year, int quarter) {
        return getSeasonStartDate(getByYearQuarter(year, quarter));
    }

    /**
     * 获取季度末日期
     */
    public static Date getSeasonEndDate(int year, int quarter) {
        return getSeasonEndDate(getByYearQuarter(year, quarter));
    }

    /**
     * 根据年和季度获取时间
     */
    private static Date getByYearQuarter(int year, int quarter) {
        String month = "01";
        if (quarter == 1) {
            month = "02";
        }
        if (quarter == 2) {
            month = "05";
        }
        if (quarter == 3) {
            month = "08";
        }
        if (quarter == 4) {
            month = "11";
        }

        return parseDate(YYYYMM, year + month);
    }

    /**
     * 根据时间获取第几季度
     */
    public static int getQuarter(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int month = cal.get(Calendar.MONTH) + 1;
        if (month <= 3) {
            return 1;
        }
        if (month <= 6) {
            return 2;
        }

        if (month <= 9) {
            return 3;
        }

        return 4;
    }

    /**
     * 获取年初日期
     */
    public static Date getYearStartDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.MONTH, 0);
        cal.set(Calendar.DATE, 1);
        return getDayStartTime(cal.getTime());
    }

    /**
     * 获取年末日期
     */
    public static Date getYearEndDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.MONTH, 11);
        return getMonthEndDate(cal.getTime());
    }

    /**
     * 获取某个日期的开始时间
     */
    public static Date getDayStartTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 获取某个日期的结束时间
     */
    public static Date getDayEndTime(Date d) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(d);
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH),
                calendar.get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 获取时间的数值
     */
    public static int getTimeInt(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.HOUR_OF_DAY);
    }

    /**
     * 获取指定年的月列表
     */
    public static List<Date> getMonthListBetween(Date start, Date end) {
        List<Date> result = new ArrayList<>();
        start = parseDate(YYYY_MM, start);
        end = parseDate(YYYY_MM, end);
        result.add(start);

        if (end.getTime() <= start.getTime()) {
            return result;
        }

        Date step = addMonth(start, 1);
        while (step.getTime() <= end.getTime()) {
            result.add(step);
            step = addMonth(step, 1);
        }

        return result;
    }

    /**
     * 获取指定年的月字符串列表
     */
    public static List<String> getMonthStrListBetween(Date start, Date end, String format) {
        List<Date> dateList = getMonthListBetween(start, end);
        if (CollectionUtils.isNotEmpty(dateList)) {
            return dateList.stream().map(x -> formatDate(format, x)).collect(Collectors.toList());
        }

        return Collections.emptyList();
    }

    /**
     * 获取指定日期所在年的月列表
     */
    public static List<Date> getYearMonthList(Date date) {
        return getMonthListBetween(getYearStartDate(date), getYearEndDate(date));
    }

    /**
     * 获取指定日期所在年的月列表
     */
    public static List<String> getYearMonthStrList(Date date, String format) {
        return getMonthStrListBetween(getYearStartDate(date), getYearEndDate(date), format);
    }

    /**
     * 获取指定日期所在年的月列表
     */
    public static List<String> getYearMonthStrList(Date date) {
        return getMonthStrListBetween(getYearStartDate(date), getYearEndDate(date), YYYYMM);
    }

    /**
     * 获取指定区间内日列表
     */
    public static List<Date> getDayListBetween(Date start, Date end) {
        List<Date> result = new ArrayList<>();
        start = parseDate(YYYY_MM, start);
        end = parseDate(YYYY_MM, end);
        result.add(start);

        if (end.getTime() <= start.getTime()) {
            return result;
        }

        Date step = addDays(start, 1);
        while (step.getTime() <= end.getTime()) {
            result.add(step);
            step = addDays(step, 1);
        }

        return result;
    }

    /**
     * 判断是否是季度最后一天
     */
    public static boolean isQuarterLastDay(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int month = cal.get(Calendar.MONTH) + 1;
        if (month % 3 != 0) {
            return false;
        }

        return getIntDay(date) == getIntDay(getMonthEndDate(date));
    }
}
